#include <glib/g2/triangulate.h>
#include <glib/g2/region.h>

#include <sstream>

extern "C" {

#define ANSI_DECLARATORS
#define REAL double
#include "triangle.h"

}

namespace g2 {

triangulation triangulate(const shape & s, double h)
{
	region r = s.flatten(h);

	size_type vcount = 0, i, j, k;
	for (i = 0; i < r.outer().size(); ++i)
		vcount += r.outer()[i].size();

	// holes are not yet supported!

	struct ::triangulateio in;
	memset(&in, 0, sizeof(struct ::triangulateio));

	in.numberofpoints = vcount;
	in.pointlist = new REAL[2 * vcount];
	k = 0;
	for (i = 0; i < r.outer().size(); ++i) {
		const contour & c = r.outer()[i];
		for (j = 0; j < c.size(); ++j) {
			in.pointlist[k++] = c[j].x;
			in.pointlist[k++] = c[j].y;
		}
	}
	in.numberofsegments = vcount;
	in.segmentlist = new int[vcount * 2];
	k = 0;
	for (i = 0; i < r.outer().size(); ++i) {
		const contour & c = r.outer()[i];
		for (j = 0; j < c.size(); ++j) {
			in.segmentlist[k++] = j;
			if (j < c.size() - 1)
				in.segmentlist[k++] = j + 1;
			else
				in.segmentlist[k++] = 0;
		}
	}

	struct ::triangulateio out;
	memset(&out, 0, sizeof(struct ::triangulateio));

	std::ostringstream sout;
	sout << "zqa" << h * h / sqrt(3.0);

	::triangulate(const_cast<char *>(sout.str().c_str()), &in, &out, 0);

	std::vector<vertex_info> vertices;
	vertices.reserve(out.numberofpoints);
	j = k = 0;
	for (i = 0; i < size_type(out.numberofpoints); ++i) {
		double x = out.pointlist[j++];
		double y = out.pointlist[j++];
		vertices.push_back(
			vertex_info(vector(x, y),
				out.pointmarkerlist[k++] != 0));
	}

	std::vector<face_info> faces;
	faces.reserve(out.numberoftriangles);
	k = 0;
	for (i = 0; i < size_type(out.numberoftriangles); ++i) {
		size_type v0 = out.trianglelist[k++];
		size_type v1 = out.trianglelist[k++];
		size_type v2 = out.trianglelist[k++];
		faces.push_back(face_info(v0, v1, v2));
	}

	delete [] in.pointlist;
	delete [] in.segmentlist;

	free(out.pointlist);
	free(out.pointmarkerlist);
	free(out.trianglelist);

	return triangulation(vertices, faces);
}

} // g2
